
/*-------------------------------------------------------------------------
 *
 * nodeAppend.c
 *	  处理附加节点的例程。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/executor/nodeAppend.c
 *
 *-------------------------------------------------------------------------
 */
/* 接口例程
 *		ExecInitAppend	- 初始化附加节点
 *		ExecAppend		- 从节点中检索下一个元组
 *		ExecEndAppend	- 关闭附加节点
 *		ExecReScanAppend - 重新扫描附加节点
 *
 *	 注意事项
 *		每个附加节点包含一个或多个子计划的列表，这些计划必须进行迭代处理（向前或向后）。
 *		通过执行'whichplan'th子计划来检索元组，直到子计划停止返回元组，此时该计划将关闭，下一计划开始。
 *
 *		附加节点不使用其左子树和右子树，而是维护一个子计划列表，因此一个典型的附加节点在计划树中看起来像这样：
 *
 *				   ...
 *				   /
 *				Append -------+------+------+--- nil
 *				/	\		  |		 |		|
 *			  nil	nil		 ...    ...    ...
 *								 子计划
 *
 *		当前，附加节点用于联合，并支持继承查询，在此查询中需要扫描多个关系。
 *		例如，在我们的标准person/student/employee/student-emp
 *		示例中，学生和员工继承自person，而学生-员工继承自学生和员工，查询：
 *
 *				select name from person
 *
 *		生成的计划是：
 *
 *				  |
 *				Append -------+-------+--------+--------+
 *				/	\		  |		  |		   |		|
 *			  nil	nil		 Scan	 Scan	  Scan	   Scan
 *							  |		  |		   |		|
 *							person employee student student-emp
 */

#include "postgres.h"

#include "executor/execAsync.h"
#include "executor/execdebug.h"
#include "executor/execPartition.h"
#include "executor/nodeAppend.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/latch.h"

/* 并行感知附加的共享状态。 */
struct ParallelAppendState
{
	LWLock		pa_lock;		/* 互斥以选择下一个子计划 */
	int			pa_next_plan;	/* 任何工作者选择的下一个计划 */

	/*
	 * pa_finished[i] 如果没有更多工作者应该选择子计划i，则应为true。
	 * 对于非部分计划，一旦工作者选择此计划，应立即设置为true；对于部分计划，保持为false，直到某个工作者执行计划完成为止。
	 */
	bool		pa_finished[FLEXIBLE_ARRAY_MEMBER];
};

#define INVALID_SUBPLAN_INDEX		-1
#define EVENT_BUFFER_SIZE			16

static TupleTableSlot *fc_ExecAppend(PlanState *fc_pstate);
static bool fc_choose_next_subplan_locally(AppendState *fc_node);
static bool fc_choose_next_subplan_for_leader(AppendState *fc_node);
static bool fc_choose_next_subplan_for_worker(AppendState *fc_node);
static void fc_mark_invalid_subplans_as_finished(AppendState *fc_node);
static void fc_ExecAppendAsyncBegin(AppendState *fc_node);
static bool fc_ExecAppendAsyncGetNext(AppendState *fc_node, TupleTableSlot **fc_result);
static bool fc_ExecAppendAsyncRequest(AppendState *fc_node, TupleTableSlot **fc_result);
static void fc_ExecAppendAsyncEventWait(AppendState *fc_node);
static void fc_classify_matching_subplans(AppendState *fc_node);

/* ----------------------------------------------------------------
 *		ExecInitAppend
 *
 *		开始所有附加节点的子扫描。
 *
 *	   （这可能会浪费，因为可能不会扫描附加节点的整个结果，但这样所有结构将在执行器的顶级内存块中分配，而不是在对ExecAppend的调用中。）
 * ----------------------------------------------------------------
 */
AppendState *
ExecInitAppend(Append *fc_node, EState *fc_estate, int fc_eflags)
{
	AppendState *fc_appendstate = makeNode(AppendState);
	PlanState **fc_appendplanstates;
	Bitmapset  *fc_validsubplans;
	Bitmapset  *fc_asyncplans;
	int			fc_nplans;
	int			fc_nasyncplans;
	int			fc_firstvalid;
	int			fc_i,
				fc_j;

	/* 检查不支持的标志 */
	Assert(!(fc_eflags & EXEC_FLAG_MARK));

	/*
	 * 为我们的附加节点创建新的AppendState
	 */
	fc_appendstate->ps.plan = (Plan *) fc_node;
	fc_appendstate->ps.state = fc_estate;
	fc_appendstate->ps.ExecProcNode = fc_ExecAppend;

	/* 让choose_next_subplan_*函数处理设置第一个子计划 */
	fc_appendstate->as_whichplan = INVALID_SUBPLAN_INDEX;
	fc_appendstate->as_syncdone = false;
	fc_appendstate->as_begun = false;

	/* 如果启用了运行时分区修剪，请立即设置该项 */
	if (fc_node->part_prune_info != NULL)
	{
		PartitionPruneState *fc_prunestate;

		/*
		 * 设置修剪数据结构。这还通过考虑执行初始修剪的结果（如果有）来初始化有效子计划的集合。
		 */
		fc_prunestate = ExecInitPartitionPruning(&fc_appendstate->ps,
											  list_length(fc_node->appendplans),
											  fc_node->part_prune_info,
											  &fc_validsubplans);
		fc_appendstate->as_prune_state = fc_prunestate;
		fc_nplans = bms_num_members(fc_validsubplans);

		/*
		 * 当不需要运行时修剪且至少有一个子计划时，我们可以立即填充as_valid_subplans，从而防止后续调用ExecFindMatchingSubPlans。
		 */
		if (!fc_prunestate->do_exec_prune && fc_nplans > 0)
			fc_appendstate->as_valid_subplans = bms_add_range(NULL, 0, fc_nplans - 1);
	}
	else
	{
		fc_nplans = list_length(fc_node->appendplans);

		/*
		 * 当未启用运行时分区修剪时，我们可以将所有子计划标记为有效；它们也必须全部初始化。
		 */
		Assert(fc_nplans > 0);
		fc_appendstate->as_valid_subplans = fc_validsubplans =
			bms_add_range(NULL, 0, fc_nplans - 1);
		fc_appendstate->as_prune_state = NULL;
	}

	/*
	 * 初始化结果元组类型和槽。
	 */
	ExecInitResultTupleSlotTL(&fc_appendstate->ps, &TTSOpsVirtual);

	/* 节点从其每个子节点返回槽，因此不固定 */
	fc_appendstate->ps.resultopsset = true;
	fc_appendstate->ps.resultopsfixed = false;

	fc_appendplanstates = (PlanState **) palloc(fc_nplans *
											 sizeof(PlanState *));

	/*
	 * 对要执行的每个有效计划调用ExecInitNode，并将结果保存到appendplanstates数组中。
	 *
	 * 在此过程中，找出第一个有效的部分计划。
	 */
	fc_j = 0;
	fc_asyncplans = NULL;
	fc_nasyncplans = 0;
	fc_firstvalid = fc_nplans;
	fc_i = -1;
	while ((fc_i = bms_next_member(fc_validsubplans, fc_i)) >= 0)
	{
		Plan	   *fc_initNode = (Plan *) list_nth(fc_node->appendplans, fc_i);

		/*
		 * 记录异步子计划。当执行EvalPlanQual时，我们将其视为同步；在初始化EvalPlanQual计划树时，不能这样做。
		 */
		if (fc_initNode->async_capable && fc_estate->es_epq_active == NULL)
		{
			fc_asyncplans = bms_add_member(fc_asyncplans, fc_j);
			fc_nasyncplans++;
		}

		/*
		 * 记录最低的appendplans索引，该索引是有效的部分计划。
		 */
		if (fc_i >= fc_node->first_partial_plan && fc_j < fc_firstvalid)
			fc_firstvalid = fc_j;

		fc_appendplanstates[fc_j++] = ExecInitNode(fc_initNode, fc_estate, fc_eflags);
	}

	fc_appendstate->as_first_partial_plan = fc_firstvalid;
	fc_appendstate->appendplans = fc_appendplanstates;
	fc_appendstate->as_nplans = fc_nplans;

	/* 初始化异步状态 */
	fc_appendstate->as_asyncplans = fc_asyncplans;
	fc_appendstate->as_nasyncplans = fc_nasyncplans;
	fc_appendstate->as_asyncrequests = NULL;
	fc_appendstate->as_asyncresults = NULL;
	fc_appendstate->as_nasyncresults = 0;
	fc_appendstate->as_nasyncremain = 0;
	fc_appendstate->as_needrequest = NULL;
	fc_appendstate->as_eventset = NULL;
	fc_appendstate->as_valid_asyncplans = NULL;

	if (fc_nasyncplans > 0)
	{
		fc_appendstate->as_asyncrequests = (AsyncRequest **)
			palloc0(fc_nplans * sizeof(AsyncRequest *));

		fc_i = -1;
		while ((fc_i = bms_next_member(fc_asyncplans, fc_i)) >= 0)
		{
			AsyncRequest *fc_areq;

			fc_areq = palloc(sizeof(AsyncRequest));
			fc_areq->requestor = (PlanState *) fc_appendstate;
			fc_areq->requestee = fc_appendplanstates[fc_i];
			fc_areq->request_index = fc_i;
			fc_areq->callback_pending = false;
			fc_areq->request_complete = false;
			fc_areq->result = NULL;

			fc_appendstate->as_asyncrequests[fc_i] = fc_areq;
		}

		fc_appendstate->as_asyncresults = (TupleTableSlot **)
			palloc0(fc_nasyncplans * sizeof(TupleTableSlot *));

		if (fc_appendstate->as_valid_subplans != NULL)
			fc_classify_matching_subplans(fc_appendstate);
	}

	/*
	 * 杂项初始化
	 */

	fc_appendstate->ps.ps_ProjInfo = NULL;

	/* 对于并行查询，稍后将覆盖此内容。 */
	fc_appendstate->choose_next_subplan = fc_choose_next_subplan_locally;

	return fc_appendstate;
}

/* ----------------------------------------------------------------
 *	   ExecAppend
 *
 *		处理多个子计划的迭代。
 * ----------------------------------------------------------------
 */
static TupleTableSlot * fc_ExecAppend(PlanState *fc_pstate)
{
	AppendState *fc_node = castNode(AppendState, fc_pstate);
	TupleTableSlot *fc_result;

	/*
	 * 如果这是Init或ReScan后的第一次调用，我们需要做初始化工作。
	 */
	if (!fc_node->as_begun)
	{
		Assert(fc_node->as_whichplan == INVALID_SUBPLAN_INDEX);
		Assert(!fc_node->as_syncdone);

		/* 如果没有子计划，则不需要做任何事情 */
		if (fc_node->as_nplans == 0)
			return ExecClearTuple(fc_node->ps.ps_ResultTupleSlot);

		/* 如果存在任何异步子计划，则开始执行它们。 */
		if (fc_node->as_nasyncplans > 0)
			fc_ExecAppendAsyncBegin(fc_node);

		/*
		 * 如果没有选择同步子计划，则必须在继续之前选择一个。
		 */
		if (!fc_node->choose_next_subplan(fc_node) && fc_node->as_nasyncremain == 0)
			return ExecClearTuple(fc_node->ps.ps_ResultTupleSlot);

		Assert(fc_node->as_syncdone ||
			   (fc_node->as_whichplan >= 0 &&
				fc_node->as_whichplan < fc_node->as_nplans));

		/* 我们已初始化。 */
		fc_node->as_begun = true;
	}

	for (;;)
	{
		PlanState  *fc_subnode;

		CHECK_FOR_INTERRUPTS();

		/*
		 * 尝试从任何异步子计划中获取元组
		 */
		if (fc_node->as_syncdone || !bms_is_empty(fc_node->as_needrequest))
		{
			if (fc_ExecAppendAsyncGetNext(fc_node, &fc_result))
				return fc_result;
			Assert(!fc_node->as_syncdone);
			Assert(bms_is_empty(fc_node->as_needrequest));
		}

		/*
		 * 确定我们当前正在处理哪个同步子计划
		 */
		Assert(fc_node->as_whichplan >= 0 && fc_node->as_whichplan < fc_node->as_nplans);
		fc_subnode = fc_node->appendplans[fc_node->as_whichplan];

		/*
		 * 从子计划获取一个元组
		 */
		fc_result = ExecProcNode(fc_subnode);

		if (!TupIsNull(fc_result))
		{
			/*
			 * 如果子计划给我们返回了内容，则按原样返回。我们不
			 * 使用在 ExecInitAppend 中设置的结果槽；没有必要。
			 */
			return fc_result;
		}

		/*
		 * 等待或轮询异步事件（如果有的话）。我们在检查
		 * 迭代结束之前这样做，因为这可能会消耗剩余的
		 * 异步子计划。
		 */
		if (fc_node->as_nasyncremain > 0)
			fc_ExecAppendAsyncEventWait(fc_node);

		/* 选择新的同步子计划；如果没有同步/异步子计划，我们就完成了 */
		if (!fc_node->choose_next_subplan(fc_node) && fc_node->as_nasyncremain == 0)
			return ExecClearTuple(fc_node->ps.ps_ResultTupleSlot);
	}
}

/* ----------------------------------------------------------------
 *		ExecEndAppend
 *
 *		关闭附加节点的子扫描。
 *
 *		不返回任何有趣的内容。
 * ----------------------------------------------------------------
 */
void ExecEndAppend(AppendState *fc_node)
{
	PlanState **fc_appendplans;
	int			fc_nplans;
	int			fc_i;

	/*
	 * 从节点获取信息
	 */
	fc_appendplans = fc_node->appendplans;
	fc_nplans = fc_node->as_nplans;

	/*
	 * 关闭每个子扫描
	 */
	for (fc_i = 0; fc_i < fc_nplans; fc_i++)
		ExecEndNode(fc_appendplans[fc_i]);
}

void ExecReScanAppend(AppendState *fc_node)
{
	int			fc_nasyncplans = fc_node->as_nasyncplans;
	int			fc_i;

	/*
	 * 如果用于修剪表达式的任何 PARAM_EXEC 参数已更改，
	 * 那我们最好取消设置有效子计划，以便为新的参数值重新选择它们。
	 */
	if (fc_node->as_prune_state &&
		bms_overlap(fc_node->ps.chgParam,
					fc_node->as_prune_state->execparamids))
	{
		bms_free(fc_node->as_valid_subplans);
		fc_node->as_valid_subplans = NULL;
		if (fc_nasyncplans > 0)
		{
			bms_free(fc_node->as_valid_asyncplans);
			fc_node->as_valid_asyncplans = NULL;
		}
	}

	for (fc_i = 0; fc_i < fc_node->as_nplans; fc_i++)
	{
		PlanState  *fc_subnode = fc_node->appendplans[fc_i];

		/*
		 * ExecReScan 不知道我的子计划，所以我必须自己进行
		 * 变化参数的信号传递。
		 */
		if (fc_node->ps.chgParam != NULL)
			UpdateChangedParamSet(fc_subnode, fc_node->ps.chgParam);

		/*
		 * 如果子节点的 chgParam 不为 null，则计划将通过
		 * 第一个 ExecProcNode 或第一个 ExecAsyncRequest 重新扫描。
		 */
		if (fc_subnode->chgParam == NULL)
			ExecReScan(fc_subnode);
	}

	/* 重置异步状态 */
	if (fc_nasyncplans > 0)
	{
		fc_i = -1;
		while ((fc_i = bms_next_member(fc_node->as_asyncplans, fc_i)) >= 0)
		{
			AsyncRequest *fc_areq = fc_node->as_asyncrequests[fc_i];

			fc_areq->callback_pending = false;
			fc_areq->request_complete = false;
			fc_areq->result = NULL;
		}

		fc_node->as_nasyncresults = 0;
		fc_node->as_nasyncremain = 0;
		bms_free(fc_node->as_needrequest);
		fc_node->as_needrequest = NULL;
	}

	/* 让choose_next_subplan_*函数处理设置第一个子计划 */
	fc_node->as_whichplan = INVALID_SUBPLAN_INDEX;
	fc_node->as_syncdone = false;
	fc_node->as_begun = false;
}

/* ----------------------------------------------------------------
 *						并行附加支持
 * ----------------------------------------------------------------
 */

/* ----------------------------------------------------------------
 *		ExecAppendEstimate
 *
 *		计算我们在并行查询 DSM 中所需的空间量，并通知 pcxt->estimator 我们的需求。
 * ----------------------------------------------------------------
 */
void ExecAppendEstimate(AppendState *fc_node,
				   ParallelContext *fc_pcxt)
{
	fc_node->pstate_len =
		add_size(offsetof(ParallelAppendState, pa_finished),
				 sizeof(bool) * fc_node->as_nplans);

	shm_toc_estimate_chunk(&fc_pcxt->estimator, fc_node->pstate_len);
	shm_toc_estimate_keys(&fc_pcxt->estimator, 1);
}


/* ----------------------------------------------------------------
 *		ExecAppendInitializeDSM
 *
 *		为并行附加设置共享状态。
 * ----------------------------------------------------------------
 */
void ExecAppendInitializeDSM(AppendState *fc_node,
						ParallelContext *fc_pcxt)
{
	ParallelAppendState *fc_pstate;

	fc_pstate = shm_toc_allocate(fc_pcxt->toc, fc_node->pstate_len);
	memset(fc_pstate, 0, fc_node->pstate_len);
	LWLockInitialize(&fc_pstate->pa_lock, LWTRANCHE_PARALLEL_APPEND);
	shm_toc_insert(fc_pcxt->toc, fc_node->ps.plan->plan_node_id, fc_pstate);

	fc_node->as_pstate = fc_pstate;
	fc_node->choose_next_subplan = fc_choose_next_subplan_for_leader;
}

/* ----------------------------------------------------------------
 *		ExecAppendReInitializeDSM
 *
 *		在开始新的扫描之前重置共享状态。
 * ----------------------------------------------------------------
 */
void ExecAppendReInitializeDSM(AppendState *fc_node, ParallelContext *fc_pcxt)
{
	ParallelAppendState *fc_pstate = fc_node->as_pstate;

	fc_pstate->pa_next_plan = 0;
	memset(fc_pstate->pa_finished, 0, sizeof(bool) * fc_node->as_nplans);
}

/* ----------------------------------------------------------------
 *		ExecAppendInitializeWorker
 *
 *		从 TOC 复制相关信息到计划状态，并初始化
 *		选择和执行最佳子计划所需的所有内容。
 * ----------------------------------------------------------------
 */
void ExecAppendInitializeWorker(AppendState *fc_node, ParallelWorkerContext *fc_pwcxt)
{
	fc_node->as_pstate = shm_toc_lookup(fc_pwcxt->toc, fc_node->ps.plan->plan_node_id, false);
	fc_node->choose_next_subplan = fc_choose_next_subplan_for_worker;
}

/* ----------------------------------------------------------------
 *		choose_next_subplan_locally
 *
 *		为非并行感知的附加选择下一个同步子计划，
 *		如果没有更多则返回 false。
 * ----------------------------------------------------------------
 */
static bool fc_choose_next_subplan_locally(AppendState *fc_node)
{
	int			fc_whichplan = fc_node->as_whichplan;
	int			fc_nextplan;

	/* 当没有子计划时我们不应被调用 */
	Assert(fc_node->as_nplans > 0);

	/* 如果 syncdone 则不用做任何事 */
	if (fc_node->as_syncdone)
		return false;

	/*
	 * 如果是第一次调用，则让 bms 成员函数通过将 whichplan 初始化为 -1
	 * 选择第一个有效的同步子计划。如果恰好没有有效的同步子计划，
	 * 则 bms 成员函数会通过返回负数来处理此情况，这将使我们能够退出并返回
	 * false 值。
	 */
	if (fc_whichplan == INVALID_SUBPLAN_INDEX)
	{
		if (fc_node->as_nasyncplans > 0)
		{
			/* 我们已经填充了 as_valid_subplans */
			Assert(fc_node->as_valid_subplans);
		}
		else if (fc_node->as_valid_subplans == NULL)
			fc_node->as_valid_subplans =
				ExecFindMatchingSubPlans(fc_node->as_prune_state, false);

		fc_whichplan = -1;
	}

	/* 确保 whichplan 在预期范围内 */
	Assert(fc_whichplan >= -1 && fc_whichplan <= fc_node->as_nplans);

	if (ScanDirectionIsForward(fc_node->ps.state->es_direction))
		fc_nextplan = bms_next_member(fc_node->as_valid_subplans, fc_whichplan);
	else
		fc_nextplan = bms_prev_member(fc_node->as_valid_subplans, fc_whichplan);

	if (fc_nextplan < 0)
	{
		/* 如果处于异步模式，则设置 as_syncdone */
		if (fc_node->as_nasyncplans > 0)
			fc_node->as_syncdone = true;
		return false;
	}

	fc_node->as_whichplan = fc_nextplan;

	return true;
}

/* ----------------------------------------------------------------
 *		choose_next_subplan_for_leader
 *
 *      尝试选择一个不会在本地承诺我们做太多工作的计划，
 *      以便尽可能多的工作在工作线程中完成。最便宜的子计划在最后。
 * ----------------------------------------------------------------
 */
static bool fc_choose_next_subplan_for_leader(AppendState *fc_node)
{
	ParallelAppendState *fc_pstate = fc_node->as_pstate;

	/* 并行感知计划不支持向后扫描 */
	Assert(ScanDirectionIsForward(fc_node->ps.state->es_direction));

	/* 当没有子计划时我们不应被调用 */
	Assert(fc_node->as_nplans > 0);

	LWLockAcquire(&fc_pstate->pa_lock, LW_EXCLUSIVE);

	if (fc_node->as_whichplan != INVALID_SUBPLAN_INDEX)
	{
		/* 将刚完成的子计划标记为已完成。 */
		fc_node->as_pstate->pa_finished[fc_node->as_whichplan] = true;
	}
	else
	{
		/* 从最后一个子计划开始。 */
		fc_node->as_whichplan = fc_node->as_nplans - 1;

		/*
		 * 如果我们尚未确定有效子计划，则现在进行确认。如果
		 * 运行时修剪被禁用，则有效子计划将始终设为所有子计划。
		 */
		if (fc_node->as_valid_subplans == NULL)
		{
			fc_node->as_valid_subplans =
				ExecFindMatchingSubPlans(fc_node->as_prune_state, false);

			/*
			 * 将每个无效计划标记为已完成，以允许下面的循环
			 * 选择第一个有效子计划。
			 */
			fc_mark_invalid_subplans_as_finished(fc_node);
		}
	}

	/* 循环直到我们找到要执行的子计划。 */
	while (fc_pstate->pa_finished[fc_node->as_whichplan])
	{
		if (fc_node->as_whichplan == 0)
		{
			fc_pstate->pa_next_plan = INVALID_SUBPLAN_INDEX;
			fc_node->as_whichplan = INVALID_SUBPLAN_INDEX;
			LWLockRelease(&fc_pstate->pa_lock);
			return false;
		}

		/*
		 * 我们在这里不需要关注 as_valid_subplans，因为所有无效的
		 * 计划已经标记为完成。
		 */
		fc_node->as_whichplan--;
	}

	/* 如果不是部分的，立即标记为完成。 */
	if (fc_node->as_whichplan < fc_node->as_first_partial_plan)
		fc_node->as_pstate->pa_finished[fc_node->as_whichplan] = true;

	LWLockRelease(&fc_pstate->pa_lock);

	return true;
}

/* ----------------------------------------------------------------
 *		choose_next_subplan_for_worker
 *
 *		为并行感知的Append选择下一个子计划，若没有更多则返回
 *		false。
 *
 *		我们从第一个计划开始，逐步向列表前进；当我们回到最后，
 *		则循环回到第一个部分计划。这首先按成本递减顺序分配
 *		非部分计划，然后尽可能均匀地分配工作者到其余的部分计划。
 * ----------------------------------------------------------------
 */
static bool fc_choose_next_subplan_for_worker(AppendState *fc_node)
{
	ParallelAppendState *fc_pstate = fc_node->as_pstate;

	/* 并行感知计划不支持向后扫描 */
	Assert(ScanDirectionIsForward(fc_node->ps.state->es_direction));

	/* 当没有子计划时我们不应被调用 */
	Assert(fc_node->as_nplans > 0);

	LWLockAcquire(&fc_pstate->pa_lock, LW_EXCLUSIVE);

	/* 将刚完成的子计划标记为已完成。 */
	if (fc_node->as_whichplan != INVALID_SUBPLAN_INDEX)
		fc_node->as_pstate->pa_finished[fc_node->as_whichplan] = true;

	/*
	 * 如果我们还没有确定有效的子计划，那现在就进行判断。如果
	 * 运行时修剪被禁用，那么有效的子计划将始终设置为所有子计划。
	 */
	else if (fc_node->as_valid_subplans == NULL)
	{
		fc_node->as_valid_subplans =
			ExecFindMatchingSubPlans(fc_node->as_prune_state, false);
		fc_mark_invalid_subplans_as_finished(fc_node);
	}

	/* 如果所有计划已经完成，我们就没有事情可做 */
	if (fc_pstate->pa_next_plan == INVALID_SUBPLAN_INDEX)
	{
		LWLockRelease(&fc_pstate->pa_lock);
		return false;
	}

	/* 保存我们开始搜索的计划。 */
	fc_node->as_whichplan = fc_pstate->pa_next_plan;

	/* 循环直到找到一个有效的子计划进行执行。 */
	while (fc_pstate->pa_finished[fc_pstate->pa_next_plan])
	{
		int			fc_nextplan;

		fc_nextplan = bms_next_member(fc_node->as_valid_subplans,
								   fc_pstate->pa_next_plan);
		if (fc_nextplan >= 0)
		{
			/* 向下一个有效计划推进。 */
			fc_pstate->pa_next_plan = fc_nextplan;
		}
		else if (fc_node->as_whichplan > fc_node->as_first_partial_plan)
		{
			/*
			 * 尝试循环回第一个有效部分计划，如果有的话。如果没有，
			 * 则安排在下面退出。
			 */
			fc_nextplan = bms_next_member(fc_node->as_valid_subplans,
									   fc_node->as_first_partial_plan - 1);
			fc_pstate->pa_next_plan =
				fc_nextplan < 0 ? fc_node->as_whichplan : fc_nextplan;
		}
		else
		{
			/*
			 * 在最后一个计划时，或者没有部分计划，或者我们已经
			 * 尝试过所有部分计划。安排退出。
			 */
			fc_pstate->pa_next_plan = fc_node->as_whichplan;
		}

		if (fc_pstate->pa_next_plan == fc_node->as_whichplan)
		{
			/* 我们已经尝试过一切！ */
			fc_pstate->pa_next_plan = INVALID_SUBPLAN_INDEX;
			LWLockRelease(&fc_pstate->pa_lock);
			return false;
		}
	}

	/* 选择我们找到的计划，并再向 pa_next_plan 推进一次。 */
	fc_node->as_whichplan = fc_pstate->pa_next_plan;
	fc_pstate->pa_next_plan = bms_next_member(fc_node->as_valid_subplans,
										   fc_pstate->pa_next_plan);

	/*
	 * 如果没有更多有效的计划，则尝试将下一个计划设置为第一个
	 * 有效部分计划。
	 */
	if (fc_pstate->pa_next_plan < 0)
	{
		int			fc_nextplan = bms_next_member(fc_node->as_valid_subplans,
											   fc_node->as_first_partial_plan - 1);

		if (fc_nextplan >= 0)
			fc_pstate->pa_next_plan = fc_nextplan;
		else
		{
			/*
			 * 没有有效的部分计划，我们已经选择了最后一个非部分计划；
			 * 所以标记我们的同事们没有更多事情可做。
			 */
			fc_pstate->pa_next_plan = INVALID_SUBPLAN_INDEX;
		}
	}

	/* 如果不是部分的，立即标记为完成。 */
	if (fc_node->as_whichplan < fc_node->as_first_partial_plan)
		fc_node->as_pstate->pa_finished[fc_node->as_whichplan] = true;

	LWLockRelease(&fc_pstate->pa_lock);

	return true;
}

/*
 * mark_invalid_subplans_as_finished
 *		将ParallelAppendState的pa_finished标记为true，
 *		对于每个无效的子计划。
 *
 * 该函数仅应在启用运行时修剪的并行Append中调用。
 */
static void fc_mark_invalid_subplans_as_finished(AppendState *fc_node)
{
	int			fc_i;

	/* 仅在并行Append模式下调用此函数有效 */
	Assert(fc_node->as_pstate);

	/* 当未启用运行时修剪时不应该被调用 */
	Assert(fc_node->as_prune_state);

	/* 如果所有计划都是有效的，则没什么可做的 */
	if (bms_num_members(fc_node->as_valid_subplans) == fc_node->as_nplans)
		return;

	/* 将所有无效计划标记为完成 */
	for (fc_i = 0; fc_i < fc_node->as_nplans; fc_i++)
	{
		if (!bms_is_member(fc_i, fc_node->as_valid_subplans))
			fc_node->as_pstate->pa_finished[fc_i] = true;
	}
}

/* ----------------------------------------------------------------
 *						异步Append支持
 * ----------------------------------------------------------------
 */

/* ----------------------------------------------------------------
 *		ExecAppendAsyncBegin
 *
 *		开始执行设计为异步能力的子计划。
 * ----------------------------------------------------------------
 */
static void fc_ExecAppendAsyncBegin(AppendState *fc_node)
{
	int			fc_i;

	/* 向后扫描不被异步感知的Append支持。 */
	Assert(ScanDirectionIsForward(fc_node->ps.state->es_direction));

	/* 当没有子计划时我们不应被调用 */
	Assert(fc_node->as_nplans > 0);

	/* 当没有异步子计划时，我们不应被调用。 */
	Assert(fc_node->as_nasyncplans > 0);

	/* 如果我们还没有确定有效的异步子计划，那么现在就进行判断。 */
	if (fc_node->as_valid_subplans == NULL)
	{
		fc_node->as_valid_subplans =
			ExecFindMatchingSubPlans(fc_node->as_prune_state, false);

		fc_classify_matching_subplans(fc_node);
	}

	/* 初始化状态变量。 */
	fc_node->as_syncdone = bms_is_empty(fc_node->as_valid_subplans);
	fc_node->as_nasyncremain = bms_num_members(fc_node->as_valid_asyncplans);

	/* 如果没有有效的异步子计划，则没什么可做的。 */
	if (fc_node->as_nasyncremain == 0)
		return;

	/* 对每个有效的异步子计划发出请求。 */
	fc_i = -1;
	while ((fc_i = bms_next_member(fc_node->as_valid_asyncplans, fc_i)) >= 0)
	{
		AsyncRequest *fc_areq = fc_node->as_asyncrequests[fc_i];

		Assert(fc_areq->request_index == fc_i);
		Assert(!fc_areq->callback_pending);

		/* 执行实际工作。 */
		ExecAsyncRequest(fc_areq);
	}
}

/* ----------------------------------------------------------------
 *		ExecAppendAsyncGetNext
 *
 *		从任何异步子计划获取下一个元组。
 * ----------------------------------------------------------------
 */
static bool fc_ExecAppendAsyncGetNext(AppendState *fc_node, TupleTableSlot **fc_result)
{
	*fc_result = NULL;

	/* 我们不应该在没有有效的异步子计划时被调用。 */
	Assert(fc_node->as_nasyncremain > 0);

	/* 异步请求一个元组。 */
	if (fc_ExecAppendAsyncRequest(fc_node, fc_result))
		return true;

	while (fc_node->as_nasyncremain > 0)
	{
		CHECK_FOR_INTERRUPTS();

		/* 等待或轮询异步事件。 */
		fc_ExecAppendAsyncEventWait(fc_node);

		/* 异步请求一个元组。 */
		if (fc_ExecAppendAsyncRequest(fc_node, fc_result))
			return true;

		/* 如果有任何未完成的同步子计划，则中断循环。 */
		if (!fc_node->as_syncdone)
			break;
	}

	/* 
	 * 如果所有同步子计划都完成，我们就完全完成了对
	 * 给定节点的扫描。否则，我们完成了异步的内容但必须
	 * 继续扫描同步子计划。
	 */
	if (fc_node->as_syncdone)
	{
		Assert(fc_node->as_nasyncremain == 0);
		*fc_result = ExecClearTuple(fc_node->ps.ps_ResultTupleSlot);
		return true;
	}

	return false;
}

/* ----------------------------------------------------------------
 *		ExecAppendAsyncRequest
 *
 *		异步请求一个元组。
 * ----------------------------------------------------------------
 */
static bool fc_ExecAppendAsyncRequest(AppendState *fc_node, TupleTableSlot **fc_result)
{
	Bitmapset  *fc_needrequest;
	int			fc_i;

	/* 如果没有需要新请求的异步子计划，则无需执行任何操作。 */
	if (bms_is_empty(fc_node->as_needrequest))
	{
		Assert(fc_node->as_nasyncresults == 0);
		return false;
	}

	/* 
	 * 如果有任何尚未返回的异步生成结果，我们无事可做；只需返回其中一个。
	 */
	if (fc_node->as_nasyncresults > 0)
	{
		--fc_node->as_nasyncresults;
		*fc_result = fc_node->as_asyncresults[fc_node->as_nasyncresults];
		return true;
	}

	/* 为每个需要的异步子计划进行新的请求。 */
	fc_needrequest = fc_node->as_needrequest;
	fc_node->as_needrequest = NULL;
	fc_i = -1;
	while ((fc_i = bms_next_member(fc_needrequest, fc_i)) >= 0)
	{
		AsyncRequest *fc_areq = fc_node->as_asyncrequests[fc_i];

		/* 执行实际工作。 */
		ExecAsyncRequest(fc_areq);
	}
	bms_free(fc_needrequest);

	/* 如果有异步生成的结果，则返回其中一个。 */
	if (fc_node->as_nasyncresults > 0)
	{
		--fc_node->as_nasyncresults;
		*fc_result = fc_node->as_asyncresults[fc_node->as_nasyncresults];
		return true;
	}

	return false;
}

/* ----------------------------------------------------------------
 *		ExecAppendAsyncEventWait
 *
 *		等待或轮询文件描述符事件并触发回调。
 * ----------------------------------------------------------------
 */
static void fc_ExecAppendAsyncEventWait(AppendState *fc_node)
{
	int			fc_nevents = fc_node->as_nasyncplans + 1;
	long		fc_timeout = fc_node->as_syncdone ? -1 : 0;
	WaitEvent	fc_occurred_event[EVENT_BUFFER_SIZE];
	int			fc_noccurred;
	int			fc_i;

	/* 我们不应该在没有有效的异步子计划时被调用。 */
	Assert(fc_node->as_nasyncremain > 0);

	Assert(fc_node->as_eventset == NULL);
	fc_node->as_eventset = CreateWaitEventSet(CurrentMemoryContext, fc_nevents);
	PG_TRY();
	{
		AddWaitEventToSet(fc_node->as_eventset, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
						  NULL, NULL);

		/* 给每个正在等待的子计划一个添加事件的机会。 */
		fc_i = -1;
		while ((fc_i = bms_next_member(fc_node->as_asyncplans, fc_i)) >= 0)
		{
			AsyncRequest *fc_areq = fc_node->as_asyncrequests[fc_i];

			if (fc_areq->callback_pending)
				ExecAsyncConfigureWait(fc_areq);
		}

		/* 
		 * 如果没有配置的事件（除了主进程死亡事件），我们不需要等待或轮询。
		 */
		if (GetNumRegisteredWaitEvents(fc_node->as_eventset) == 1)
			fc_noccurred = 0;
		else
		{
			/* 在一次调用中最多返回 EVENT_BUFFER_SIZE 个事件。 */
			if (fc_nevents > EVENT_BUFFER_SIZE)
				fc_nevents = EVENT_BUFFER_SIZE;

			/* 
			 * 如果超时为 -1，等待直到至少发生一个事件。如果
			 * 超时为 0，则轮询事件，但不等待。
			 */
			fc_noccurred = WaitEventSetWait(fc_node->as_eventset, fc_timeout,
										 fc_occurred_event, fc_nevents,
										 WAIT_EVENT_APPEND_READY);
		}
	}
	PG_FINALLY();
	{
		FreeWaitEventSet(fc_node->as_eventset);
		fc_node->as_eventset = NULL;
	}
	PG_END_TRY();
	if (fc_noccurred == 0)
		return;

	/* 传递通知。 */
	for (fc_i = 0; fc_i < fc_noccurred; fc_i++)
	{
		WaitEvent  *fc_w = &fc_occurred_event[fc_i];

		/* 
		 * 每个等待的子计划应该已经将其等待事件注册，并且
		 * user_data 指向其 AsyncRequest。
		 */
		if ((fc_w->events & WL_SOCKET_READABLE) != 0)
		{
			AsyncRequest *fc_areq = (AsyncRequest *) fc_w->user_data;

			if (fc_areq->callback_pending)
			{
				/* 
				 * 标记为不再需要回调。我们必须在调度回调之前
				 * 执行此操作，以防回调重置标志。
				 */
				fc_areq->callback_pending = false;

				/* 执行实际工作。 */
				ExecAsyncNotify(fc_areq);
			}
		}
	}
}

/* ----------------------------------------------------------------
 *		ExecAsyncAppendResponse
 *
 *		接收我们发出的异步请求的响应。
 * ----------------------------------------------------------------
 */
void ExecAsyncAppendResponse(AsyncRequest *fc_areq)
{
	AppendState *fc_node = (AppendState *) fc_areq->requestor;
	TupleTableSlot *fc_slot = fc_areq->result;

	/* 结果应该是一个 TupleTableSlot 或 NULL。 */
	Assert(fc_slot == NULL || IsA(fc_slot, TupleTableSlot));

	/* 如果请求仍在等待，则无事可做。 */
	if (!fc_areq->request_complete)
	{
		/* 请求可能已等待回调。 */
		Assert(fc_areq->callback_pending);
		return;
	}

	/* 如果结果为 NULL 或为空槽，则不再有其他操作。 */
	if (TupIsNull(fc_slot))
	{
		/* 最终的子计划不会等待回调。 */
		Assert(!fc_areq->callback_pending);
		--fc_node->as_nasyncremain;
		return;
	}

	/* 保存结果，以便我们可以返回它。 */
	Assert(fc_node->as_nasyncresults < fc_node->as_nasyncplans);
	fc_node->as_asyncresults[fc_node->as_nasyncresults++] = fc_slot;

	/* 
	 * 将返回结果的子计划标记为准备好进行新请求。我们
	 * 不会立即在这里启动另一个请求，因为它可能会完成。
	 */
	fc_node->as_needrequest = bms_add_member(fc_node->as_needrequest,
										  fc_areq->request_index);
}

/* ----------------------------------------------------------------
 *		classify_matching_subplans
 *
 *		将节点的 as_valid_subplans 分类为同步和
 *		异步节点，将其调整为仅包含同步节点，并将
 *		异步节点保存在节点的 as_valid_asyncplans 中。
 * ----------------------------------------------------------------
 */
static void fc_classify_matching_subplans(AppendState *fc_node)
{
	Bitmapset  *fc_valid_asyncplans;

	Assert(fc_node->as_valid_asyncplans == NULL);

	/* 如果没有有效的子计划，则无事可做。 */
	if (bms_is_empty(fc_node->as_valid_subplans))
	{
		fc_node->as_syncdone = true;
		fc_node->as_nasyncremain = 0;
		return;
	}

	/* 如果没有有效的异步子计划，则没什么可做的。 */
	if (!bms_overlap(fc_node->as_valid_subplans, fc_node->as_asyncplans))
	{
		fc_node->as_nasyncremain = 0;
		return;
	}

	/* 获取有效的异步子计划。 */
	fc_valid_asyncplans = bms_copy(fc_node->as_asyncplans);
	fc_valid_asyncplans = bms_int_members(fc_valid_asyncplans,
									   fc_node->as_valid_subplans);

	/* 将有效的子计划调整为仅包含同步子计划。 */
	fc_node->as_valid_subplans = bms_del_members(fc_node->as_valid_subplans,
											  fc_valid_asyncplans);

	/* 保存有效的异步子计划。 */
	fc_node->as_valid_asyncplans = fc_valid_asyncplans;
}
